16. RCC

您所在的位置:网站首页 超频失败 g0 16. RCC

16. RCC

2024-06-14 16:00| 来源: 网络整理| 查看: 265

16.3.4.2. 代码分析¶

这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到, 完整的代码请参考本章配套的工程。

使用HSE配置系统时钟

代码清单:RCC-2 使用HSE配置系统时钟¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85/* * 使用HSE时,设置系统时钟的步骤 * 1、开启HSE ,并等待 HSE 稳定 * 2、设置 AHB、APB2、APB1的预分频因子 * 3、设置PLL的时钟来源 * 设置VCO输入时钟 分频因子 m * 设置VCO输出时钟 倍频因子 n * 设置PLLCLK时钟分频因子 p * 设置OTG FS,SDIO,RNG时钟分频因子 q * 4、开启PLL,并等待PLL稳定 * 5、把PLLCK切换为系统时钟SYSCLK * 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟 */ /* * m: VCO输入时钟 分频因子,取值2~63 * n: VCO输出时钟 倍频因子,取值192~432 * p: PLLCLK时钟分频因子 ,取值2,4,6,8 * q: OTG FS,SDIO,RNG时钟分频因子,取值4~15 * 函数调用举例,使用HSE设置时钟 * SYSCLK=HCLK=168M,PCLK2=HCLK/2=84M,PCLK1=HCLK/4=42M * HSE_SetSysClock(25, 336, 2, 7); * HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法 * 系统时钟超频到216M爽一下 * HSE_SetSysClock(25, 432, 2, 9); */ void HSE_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q) { __IO uint32_t HSEStartUpStatus = 0; // 使能HSE,开启外部晶振,野火F407使用 HSE=25M RCC_HSEConfig(RCC_HSE_ON); // 等待HSE启动稳定 HSEStartUpStatus = RCC_WaitForHSEStartUp(); if (HSEStartUpStatus == SUCCESS) { // 调压器电压输出级别配置为1,以便在器件为最大频率 // 工作时使性能和功耗实现平衡 RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; // HCLK = SYSCLK / 1 RCC_HCLKConfig(RCC_SYSCLK_Div1); // PCLK2 = HCLK / 2 RCC_PCLK2Config(RCC_HCLK_Div2); // PCLK1 = HCLK / 4 RCC_PCLK1Config(RCC_HCLK_Div4); // 如果要超频就得在这里下手啦 // 设置PLL来源时钟,设置VCO分频因子m,设置VCO倍频因子n, // 设置系统时钟分频因子p,设置OTG FS,SDIO,RNG分频因子q RCC_PLLConfig(RCC_PLLSource_HSE, m, n, p, q); // 使能PLL RCC_PLLCmd(ENABLE); // 等待 PLL稳定 while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /*-----------------------------------------------------*/ // 配置FLASH预取指,指令缓存,数据缓存和等待状态 FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS; /*-----------------------------------------------------*/ // 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 读取时钟切换状态位,确保PLLCLK被选为系统时钟 while (RCC_GetSYSCLKSource() != 0x08) { } } else { // HSE启动出错处理 while (1) { } } }

这个函数采用库函数编写, 代码理解参考注释即可。函数有4个形参m、n、p、q,具体说明见下表。

形参

形参说明

取值范围

m

VCO输入时钟 分频因子

2~63

n

VCO输出时钟 倍频因子

192~432

p

PLLCLK时钟分频因子

2/4/6/8

q

OTG FS,SDIO,RNG时钟分频因子

4~15

HSE我们使用25M,参数m我们一般也设置为25,所以我们需要修改系统时钟的时候只需要修改参数n和p即可,SYSCLK=PLLCLK=HSE/m*n/p。

函数调用举例:HSE_SetSysClock(25, 336, 2, 7) 把系统时钟设置为168M,这个跟库里面的系统时钟配置是一样的。 HSE_SetSysClock(25, 432, 2, 9)把系统时钟设置为216M,这个是超频,要慎用。

使用HSI配置系统时钟

代码清单:RCC-3 使用HSI配置系统时钟¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89/* * 使用HSI时,设置系统时钟的步骤 * 1、开启HSI ,并等待 HSI 稳定 * 2、设置 AHB、APB2、APB1的预分频因子 * 3、设置PLL的时钟来源 * 设置VCO输入时钟 分频因子 m * 设置VCO输出时钟 倍频因子 n * 设置SYSCLK时钟分频因子 p * 设置OTG FS,SDIO,RNG时钟分频因子 q * 4、开启PLL,并等待PLL稳定 * 5、把PLLCK切换为系统时钟SYSCLK * 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟 */ /* * m: VCO输入时钟 分频因子,取值2~63 * n: VCO输出时钟 倍频因子,取值192~432 * p: PLLCLK时钟分频因子 ,取值2,4,6,8 * q: OTG FS,SDIO,RNG时钟分频因子,取值4~15 * 函数调用举例,使用HSI设置时钟 * SYSCLK=HCLK=168M,PCLK2=HCLK/2=84M,PCLK1=HCLK/4=42M * HSI_SetSysClock(16, 336, 2, 7); * HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法 * 系统时钟超频到216M爽一下 * HSI_SetSysClock(16, 432, 2, 9); */ void HSI_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q) { __IO uint32_t HSIStartUpStatus = 0; // 把RCC外设初始化成复位状态 RCC_DeInit(); //使能HSI, HSI=16M RCC_HSICmd(ENABLE); // 等待 HSI 就绪 HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY; // 只有 HSI就绪之后则继续往下执行 if (HSIStartUpStatus == RCC_CR_HSIRDY) { // 调压器电压输出级别配置为1,以便在器件为最大频率 // 工作时使性能和功耗实现平衡 RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; // HCLK = SYSCLK / 1 RCC_HCLKConfig(RCC_SYSCLK_Div1); // PCLK2 = HCLK / 2 RCC_PCLK2Config(RCC_HCLK_Div2); // PCLK1 = HCLK / 4 RCC_PCLK1Config(RCC_HCLK_Div4); // 如果要超频就得在这里下手啦 // 设置PLL来源时钟,设置VCO分频因子m,设置VCO倍频因子n, // 设置系统时钟分频因子p,设置OTG FS,SDIO,RNG分频因子q RCC_PLLConfig(RCC_PLLSource_HSI, m, n, p, q); // 使能PLL RCC_PLLCmd(ENABLE); // 等待 PLL稳定 while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /*-----------------------------------------------------*/ // 配置FLASH预取指,指令缓存,数据缓存和等待状态 FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; /*-----------------------------------------------------*/ // 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 读取时钟切换状态位,确保PLLCLK被选为系统时钟 while (RCC_GetSYSCLKSource() != 0x08) { } } else { // HSI启动出错处理 while (1) { } } }

这个函数采用库函数编写, 代码理解参考注释即可。函数有4个形参m、n、p、q,具体说明见下表。

形参

形参说明

取值范围

m

VCO输入时钟 分频因子

2~63

n

VCO输出时钟 倍频因子

192~432

p

PLLCLK时钟分频因子

2/4/6/8

q

OTG FS,SDIO,RNG时钟分频因子

4~15

HSI为16M,参数m我们一般也设置为16,所以我们需要修改系统时钟的时候只需要修改参数n和p即可,SYSCLK=PLLCLK=HSI/m*n/p。

函数调用举例:HSI_SetSysClock(16, 336, 2, 7) 把系统时钟设置为168M,这个跟库里面的系统时钟配置是一样的。 HSI_SetSysClock(16, 432, 2, 9)把系统时钟设置为216M,这个是超频,要慎用。

软件延时

void Delay(__IO uint32_t nCount) { for (; nCount != 0; nCount--); }

软件延时函数,使用不同的系统时钟,延时时间不一样,可以通过LED闪烁的频率来判断。

MCO输出

在F407中,PA8/PC9可以复用为MCO1/2引脚,对外提供时钟输出,我们也可以用示波器监控该引脚的输出来判断我们的系统时钟是否设置正确。

代码清单:RCC-4 MCO GPIO初始化¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29// MCO1 PA8 GPIO 初始化 void MCO1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // MCO1 GPIO 配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStructure); } // MCO2 PC9 GPIO 初始化 void MCO2_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); // MCO2 GPIO 配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOC, &GPIO_InitStructure); }

野火F407开发板中PA8与 PC9都引出来了,在摄像头接口位置,都可以使用示波器来监控波形。

代码清单:RCC-5 MCO输出时钟选择¶ 1 2 3 4 5// MCO1 输出PLLCLK RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_1); // MCO1 输出SYSCLK RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO1Div_1);

我们初始化MCO引脚之后,可以直接调用库函数RCC_MCOxConfig()来选择MCO时钟来源,同时还可以分频,这两个参数的取值参考库函数说明即可。

主函数

代码清单:RCC-6 main函数¶ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55// 使用HSE或者HSI 配置系统时钟 #include "stm32f4xx.h" #include "./rcc/bsp_clkconfig.h" #include "./led/bsp_led.h" void Delay(__IO u32 nCount); /** * @brief 主函数 * @param 无 * @retval 无 */ int main(void) { // 程序来到main函数之前,启动文件:statup_stm32f4xx.s已经调用 // SystemInit()函数把系统时钟初始化成168MHZ // SystemInit()在system_stm32f4xx.c中定义 // 如果用户想修改系统时钟,可自行编写程序修改 // 重新设置系统时钟,这时候可以选择使用HSE还是HSI // 使用HSE,配置系统时钟为168M HSE_SetSysClock(25, 336, 2, 7); //系统时钟超频到216M爽一下,最高是216M,别往死里整 //HSE_SetSysClock(25, 432, 2, 9); // 使用HSI,配置系统时钟为168M // HSI_SetSysClock(16, 336, 2, 7); // LED 端口初始化 LED_GPIO_Config(); // MCO GPIO 初始化 MCO1_GPIO_Config(); MCO2_GPIO_Config(); // MCO1 输出PLLCLK RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_1); // MCO2 输出SYSCLK RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO1Div_1); while (1) { LED1( ON ); // 亮 Delay(0x0FFFFF); LED1( OFF ); // 灭 Delay(0x0FFFFF); } } void Delay(__IO uint32_t nCount) //简单的延时函数 { for (; nCount != 0; nCount--); }

在主函数中,可以调用HSE_SetSysClock()或者HSI_SetSysClock()这两个函数把系统时钟设置成各种常用的时钟,然后通过MCO引脚监控, 或者通过LED闪烁的快慢体验不同的系统时钟对同一个软件延时函数的影响。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3